// CommWin32.cpp: implementation of the CCommWin32 class.
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "gmp.h"
#include "CommWin32.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

CCommWin32::CCommWin32()
{
	m_hCom = INVALID_HANDLE_VALUE;
	inQue = outQue = 0;
	m_bOpen = FALSE;

	memset(&m_dcb, 0, sizeof(m_dcb) );
	m_dcb.DCBlength = sizeof( m_dcb );
	m_dcb.BaudRate = CBR_9600;
	m_dcb.ByteSize = DATABITS_8;
	m_dcb.StopBits = ONESTOPBIT;
	m_dcb.fParity = FALSE;
	m_dcb.Parity = NOPARITY;
	m_dcb.fRtsControl = RTS_CONTROL_ENABLE;		// set RTS bit high!
}

CCommWin32::~CCommWin32()
{
	if( m_pProtocol ) 
		delete m_pProtocol;
	m_pProtocol = NULL;
	Close();
}


BOOL CCommWin32::InitParam(int recno, CGlobalConfigParam * pmemParam )
{
	BOOL bResult = TRUE;
	CString comname;
    
	m_recno =  recno;//for diagnose 
	if( pmemParam == NULL ) 
		return FALSE;
	
	
	comname.Format("COMM%d",this->m_recno);
	m_iPortNo =  ::GetPrivateProfileInt(comname,"Port",1,CFG_FILE);
	m_dcb.BaudRate = ::GetPrivateProfileInt(comname,"BaudRate",9600,CFG_FILE);
	m_dcb.StopBits = ::GetPrivateProfileInt(comname,"StopBits",1,CFG_FILE);
	m_dcb.ByteSize = ::GetPrivateProfileInt(comname,"ByteSize",8,CFG_FILE);
	m_dcb.Parity = ::GetPrivateProfileInt(comname,"Parity",0,CFG_FILE);
	

	//must executive parent class member
	if( !CCommAsync::InitParam(recno, pmemParam ) )
		return FALSE;
	if( !Open() )
		return FALSE;
//	AfxBeginThread( InitPort, this );
	return bResult;
}

UINT CCommWin32::InitPort( LPVOID pParam)
{
	if( pParam == NULL )
		return 0;
	CCommWin32 * pDest = (CCommWin32*)pParam;
	pDest->Open();
	return 0;
}

BOOL CCommWin32::Open()
{
	if(m_hCom != INVALID_HANDLE_VALUE ) 
		return TRUE;
	m_bOpen = FALSE;
	CString sztemp;
	sztemp.Format("%d", m_iPortNo);
	sztemp = _T("\\\\.\\COM") + sztemp;
	m_hCom = CreateFile( sztemp, 
						  GENERIC_READ | GENERIC_WRITE,
						  0,
						  NULL,
						  OPEN_EXISTING,
						  0,
						  NULL );
	UINT no = GetLastError();
	if( m_hCom != INVALID_HANDLE_VALUE )
	{
		DCB dcb;
		dcb.DCBlength = sizeof(DCB);
		if( PurgeComm( m_hCom , PURGE_RXCLEAR|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_TXABORT ) )
		{
			if( GetCommState( m_hCom, &dcb) )
			{
				dcb.BaudRate = m_dcb.BaudRate;
				dcb.ByteSize = m_dcb.ByteSize;
				dcb.StopBits = m_dcb.StopBits;
				dcb.fBinary = m_dcb.fBinary;
				dcb.Parity = m_dcb.Parity;
				dcb.fRtsControl = m_dcb.fRtsControl;
				dcb.fDtrControl = DTR_CONTROL_ENABLE;
				dcb.fTXContinueOnXoff = 0;

				if( SetCommState( m_hCom, &dcb) )
				{
					if( SetupComm( m_hCom,512,512) )
					{
						COMMTIMEOUTS CommTimeOuts;
						CommTimeOuts.ReadIntervalTimeout = MAXDWORD;
						CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
						CommTimeOuts.ReadTotalTimeoutConstant = 0;
						CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
						CommTimeOuts.WriteTotalTimeoutConstant = 0;
						if( SetCommTimeouts( m_hCom, &CommTimeOuts ) )
						{
							m_bOpen = TRUE;
						}
					}
				}
			}
		}
	}
	if(!m_bOpen )
		Close();
	return TRUE;
}

BOOL CCommWin32::Close()
{
	if( m_hCom != INVALID_HANDLE_VALUE )
	{
		PurgeComm( m_hCom , PURGE_RXCLEAR|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_TXABORT );
		CloseHandle( m_hCom );
	}
	m_hCom = NULL;
	m_bOpen = FALSE;
	return TRUE;
}

int CCommWin32::Read(BYTE *pBuf, int max)
{
	if(m_hCom == INVALID_HANDLE_VALUE) 
		return 0;
	if( pBuf == NULL || !::AfxIsValidAddress(pBuf, max, FALSE ) ) 
		return 0;
	if( !m_bOpen ) 
		return 0;
	BOOL bReadStatus;
	DWORD dwBytesRead, dwErrorFlags;
	COMSTAT ComStat;
	ClearCommError( m_hCom, &dwErrorFlags, &ComStat );
	if( !ComStat.cbInQue )
		return( 0 );
	dwBytesRead = (DWORD) ComStat.cbInQue;
	if( max < (int) dwBytesRead ) 
		dwBytesRead = (DWORD) max;

	bReadStatus = ReadFile( m_hCom, pBuf, dwBytesRead, &dwBytesRead , NULL);
	if( !bReadStatus )
		return 0;
	return( (int) dwBytesRead );
}

int CCommWin32::Write(BYTE *pBuf, int len)
{
	if( !m_bOpen ) 
		return 0;
	DWORD dwResult = 0; 
	int inter = 1, oldlen = len;
	int once = 12;
	if(m_hCom != INVALID_HANDLE_VALUE && outQue <= 0 )
	{
		BOOL bResult;
		while( len >= once )
		{
			bResult = WriteFile(m_hCom, pBuf, once, &dwResult,NULL);
			if( bResult )
			{
				if( m_dcb.fParity )
					inter = (int)(once*11.0/m_dcb.BaudRate*1000+0.5);
				else
					inter = (int)(once*10/m_dcb.BaudRate*1000+0.5);

				Sleep( inter );
			}else
				UINT errcode = ::GetLastError();

			len -= dwResult;
			pBuf += dwResult;
		}
		if( len > 0 )
		{
			if( WriteFile( m_hCom, pBuf, (DWORD)len, &dwResult, NULL ) )
			{
				if( m_dcb.fParity )
					inter = (int)(len*11.0/m_dcb.BaudRate*1000+0.5);
				else
					inter = (int)(len*10.0/m_dcb.BaudRate*1000+0.5);

				Sleep( inter );
				
				len -= dwResult;
			}
		}
	}
	return (oldlen-len);
}


BOOL CCommWin32::ClearError()
{
	if( m_hCom == INVALID_HANDLE_VALUE )
		return FALSE;
	DWORD dwError;
	COMSTAT stat;
	if( !::ClearCommError(m_hCom, &dwError, &stat ) )
	{
		PurgeComm( m_hCom , PURGE_RXCLEAR|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_TXABORT );
		inQue = 0;
		outQue = 100;
		return FALSE;
	}else{
		inQue = stat.cbInQue; 
		outQue = stat.cbOutQue;
	}
	if( dwError & CE_RXOVER )
		PurgeComm( m_hCom , PURGE_RXCLEAR|PURGE_RXABORT );
	if( dwError & CE_TXFULL )
		PurgeComm( m_hCom , PURGE_TXCLEAR|PURGE_TXABORT );
	if( outQue > 3 )
		return FALSE;
	return TRUE;
}

int CCommWin32::GetDiagnoseStatus()
{
	if( !m_bOpen || m_hCom == INVALID_HANDLE_VALUE )
		return STATUS_FAULT;
	return STATUS_NORMAL;
}
